package com.dmai.capacity.platform.gateway.error;

import java.net.ConnectException;
import java.util.HashMap;
import java.util.Map;

import com.dmai.capacity.platform.common.constant.UaaConstant;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.buffer.DataBufferLimitException;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;

import com.dmai.capacity.platform.common.constant.CommonConstant;

import lombok.extern.slf4j.Slf4j;

/**
 * 自定义异常处理
 */
@Slf4j
@SuppressWarnings(value = {"all"})
public class CustomerWebExceptionHandler
        extends org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler {
    public CustomerWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties.Resources resources,
                                       ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resources, errorProperties, applicationContext);
    }

    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        // 这里可以根据异常类型进行定制化逻辑
        int status = CommonConstant.FAIL;
        Throwable error = super.getError(request);
        Map<String, Object> errorAttributes = new HashMap<>(4);
        errorAttributes.put(CommonConstant.STATUS, status);
        String message = error.getMessage();
        if (error instanceof NotFoundException) {
            NotFoundException e = (NotFoundException) error;
            HttpStatus httpStatus = e.getStatus();
            if (404 == httpStatus.value()) {
                message = "接口访问404,请查看路由信息是否正确";
                errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.NOT_FOUND.value());
            } else if (503 == httpStatus.value()) {
                Route route = request.exchange().getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
                message = "服务不可用";
                errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.SERVICE_UNAVAILABLE.value());
            }
        } else if (error instanceof ResponseStatusException) {
            if (404 == ((ResponseStatusException) error).getStatus().value()) {
                message = "接口访问404,请查看路由信息是否正确或者当前服务是否正常";
            } else {
                message = "其他异常！";
            }
            errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.INTERNAL_SERVER_ERROR.value());
        } else if (error instanceof InvalidTokenException) {
            errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.UNAUTHORIZED.value());
            errorAttributes.put(CommonConstant.STATUS, UaaConstant.AUTH_CODE_INVALID_TOKEN);
            message = "无效的Access_token";
        } else if (error instanceof DataBufferLimitException) {
            errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.PAYLOAD_TOO_LARGE.value());
            message = "请求数据超过限定大小";
        } else if (error instanceof ConnectException) {
            errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.SERVICE_UNAVAILABLE.value());
            message = "内部服务异常";
        } else if (error instanceof BadSqlGrammarException) {
            errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.INTERNAL_SERVER_ERROR.value());
            message = "服务运行SQLException异常";
        } else {
            errorAttributes.put(CommonConstant.RESPONSE_STATUS, HttpStatus.INTERNAL_SERVER_ERROR.value());
        }

        errorAttributes.put("msg", message);
        log.error("{} {}, error:{}", request.methodName(), request.path(), errorAttributes);
        return errorAttributes;
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {
        return super.getHttpStatus(errorAttributes);
    }
}
